package com.nage.components.collision;

import android.util.Log;

import com.nage.components.movement.Physics;
import com.nage.components.movement.Vector2D;

public class Collision {

	Collidable collidable1, collidable2;

	boolean remove; // this collision needs to be removed from table. done to
					// avoid concurrent modification exception

	public Collision(Collidable c, Collidable d) {
		this.collidable1 = c;
		this.collidable2 = d;
	}

	public boolean isBetween(Collidable c, Collidable d) {
		if ((collidable1.equals(c) && collidable2.equals(d))
				|| (collidable1.equals(d) && collidable2.equals(c))) {
			return true;
		}
		return false;
	}
	
	public Vector2D getCollisionPoint() {
		
		Vector2D vertex, pVertex;
		vertex = new Vector2D();
		pVertex = new Vector2D();
		for (int i = 0; i < 4; i++) {
			if (i == 0) {
				// bottom left, etc.
				vertex.set(collidable2.mask.left, collidable2.mask.bottom);
				pVertex.set(collidable2.mask.pLeft, collidable2.mask.pBottom);
			}
			if (i == 1) {
				vertex.set(collidable2.mask.right, collidable2.mask.bottom);
				pVertex.set(collidable2.mask.pRight, collidable2.mask.pBottom);
			}
			if (i == 2) {
				vertex.set(collidable2.mask.left, collidable2.mask.top);
				pVertex.set(collidable2.mask.pLeft, collidable2.mask.pTop);
			}
			if (i == 3) {
				vertex.set(collidable2.mask.right, collidable2.mask.top);
				pVertex.set(collidable2.mask.pRight, collidable2.mask.pTop);
			}

			if (vertex.x > collidable1.mask.left
					&& vertex.x < collidable1.mask.right
					&& vertex.y > collidable1.mask.bottom
					&& vertex.y < collidable1.mask.top) {
				// this vertex is within the mask of the shape.

				Vector2D sideA, sideB; // represents the edge of a shape
				sideA = new Vector2D();
				sideB = new Vector2D();
				for(int j = 0; j < 4; j++) {
					if(j==0) {
						// set it to left edge
						sideA.set(collidable1.mask.left, collidable1.mask.bottom);
						sideB.set(collidable1.mask.left, collidable1.mask.top);
					}
					if(j==1) {
						// set to top edge
						sideA.set(collidable1.mask.right, collidable1.mask.top);
					}
					if(j==2) {
						// set to right edge
						sideB.set(collidable1.mask.right, collidable1.mask.bottom);
					}
					if(j==3) {
						sideA.set(collidable1.mask.left, collidable1.mask.bottom);
					}
					
					
				
					if(intersects(vertex, pVertex, sideA, sideB)) {
						return intersectionPoint(vertex, pVertex, sideA, sideB);
					}
				
				}
				
			}
		}
		return null;
	
	}
	
	

	private Vector2D intersectionPoint(Vector2D p1, Vector2D p2,
			Vector2D p3, Vector2D p4) {

	    float d = ((p4.y - p3.y) * (p2.x - p1.x)) - ((p4.x - p3.x) * (p2.y - p1.y));
	    float n1 = ((p4.x - p3.x) * (p1.y - p3.y)) - ((p4.y - p3.y) * (p1.x - p3.x));
	    float n2 = ((p2.x - p1.x) * (p1.y - p3.y)) - ((p2.y - p1.y) * (p1.x - p3.x));

	    if ( d == 0.0 )
	    {
	        if ( n1 == 0.0 && n2 == 0.0 )
	    		{
	            return null;  //COINCIDENT;
	        }

	        return null;	// PARALLEL;
	    }

	    float ua = n1 / d;
//	    float ub = n2 / d;

	   float x = p1.x + ua * (p2.x - p1.x);
	   float y = p1.y + ua * (p2.y - p1.y);

	    return new Vector2D(x, y);
	
	}

	private boolean intersects(Vector2D p1, Vector2D p2,
			Vector2D p3, Vector2D p4) {

	    float d = ((p4.y - p3.y) * (p2.x - p1.x)) - ((p4.x - p3.x) * (p2.y - p1.y));
	    float n1 = ((p4.x - p3.x) * (p1.y - p3.y)) - ((p4.y - p3.y) * (p1.x - p3.x));
	    float n2 = ((p2.x - p1.x) * (p1.y - p3.y)) - ((p2.y - p1.y) * (p1.x - p3.x));

	    if ( d == 0.0 )
	    {
	        if ( n1 == 0.0 && n2 == 0.0 )
	        {
	            return false;  //COINCIDENT;
	        }

	        return false;   // PARALLEL;
	    }

	    float ua = n1 / d;
	    float ub = n2 / d;

	    return (ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0);
	
	}

	public Vector2D getCollisionNormal() {
		// 1. calculate which side of collidable1 the collision occured on

	//	Log.d("Collision", "Collidable1 = "+collidable1.parent.name+", Collidable2 = "+collidable2.parent.name);
		
		Vector2D vertex;
		vertex = new Vector2D();
		for (int i = 0; i < 4; i++) {
			if (i == 0) {
				// bottom left, etc.
				vertex.set(collidable2.mask.left, collidable2.mask.bottom);
			}
			if (i == 1) {
				vertex.set(collidable2.mask.right, collidable2.mask.bottom);
			}
			if (i == 2) {
				vertex.set(collidable2.mask.left, collidable2.mask.top);
			}
			if (i == 3) {
				vertex.set(collidable2.mask.right, collidable2.mask.top);
			}

			if (vertex.x > collidable1.mask.left
					&& vertex.x < collidable1.mask.right) {
			//	Log.d("Collision", "Collision between i("+i+") of Collidable2 and top/bottom of Collidable1");
				//Log.d("Collision", "Collidable2 y="+vertex.y+", Collidable1 top="+collidable1.mask.top+", bottom="+collidable1.mask.bottom);

				// this vertex is within the left/right bounds of mask. could be top/bottom collision
				// is this vertex within the top/bottom bounds of mask. if so, this vertex is part of the collision.
				// was the vertexes previous position higher? then it has collided with the top.
				// or was the vertexes previous position lower? then it has collided with the top.
				if(vertex.y < collidable1.mask.top
						&& vertex.y > collidable1.mask.bottom) {
					if(collidable2.mask.pBottom > collidable2.mask.bottom) {
						// previous position is higher than current position. hit top.
						Log.d("Collision", "Between vertex("+i+") of "+collidable2.parent.m_Name+" on top edge of "+collidable1.parent.m_Name);
						return new Vector2D(0, 1);
					} else if (collidable2.mask.pBottom < collidable2.mask.bottom) {
						// previous position is lower than current position. hit bottom.
						Log.d("Collision", "Between vertex("+i+") of "+collidable2.parent.m_Name+" on bottom edge of "+collidable1.parent.m_Name);
						return new Vector2D(0, -1);
					} else {
						// contact.
					}
				}
								
			} else if (vertex.y > collidable1.mask.bottom
					&& vertex.y < collidable1.mask.top) {
				// test vertex has collided with collidable 1 at some point between the top and bottom,
				// so it hit either on the left of the right.
				if(vertex.x > collidable1.mask.left
						&& vertex.x < collidable1.mask.right) {
					// this vertex has definitely penetrated the collidable. was it moving left or right?
					if(collidable2.mask.pLeft > collidable2.mask.left) {
						// moving left, so collision on right edge
						Log.d("Collision", "Between vertex("+i+") of "+collidable2.parent.m_Name+" on right edge of "+collidable1.parent.m_Name);
						return new Vector2D(1, 0);
					} else if (collidable2.mask.pLeft < collidable2.mask.left) {
						// moving right, so collision on left edge
						Log.d("Collision", "Between vertex("+i+") of "+collidable2.parent.m_Name+" on left edge of "+collidable1.parent.m_Name);
						return new Vector2D(-1, 0);
					} else {
						// contact
					}
				}
				
			}
		}

		Log.w("Collision", "Cannot calculate collision normal!!");
		return null;
	}

	public Vector2D getVelocityDifference() {
		Physics col1P = collidable1.m_Physics;
		Physics col2P = collidable2.m_Physics;
		col1P.printDetails();
		col2P.printDetails();
		Vector2D col1V = col1P.vel;
		Vector2D col2V = col2P.vel;
		return col1V.minus(col2V);
	}

	public Vector2D getCollisionNormal(Vector2D collisionPoint) {
		if(collisionPoint.x==collidable1.mask.left) {
			return new Vector2D(-1, 0);
		}
		if(collisionPoint.x==collidable1.mask.right) {
			return new Vector2D(1, 0);
		}
		if(collisionPoint.y==collidable1.mask.top) {
			return new Vector2D(0, 1);
		}
		if(collisionPoint.y==collidable1.mask.bottom) {
			return new Vector2D(0, -1);
		}
		return null;
		
	}

	public Collidable getOtherCollidable(Collidable c) {
		if(c.equals(collidable1)) {
			return collidable2;
		}
		if(c.equals(collidable2)) {
			return collidable1;
		}
		return null;
	}

}
